package com.binance.mbxgateway.web.service.impl;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import com.binance.mbxgateway.data.mapper.UserModelMapper;
import com.google.common.collect.Maps;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import org.springframework.web.client.HttpStatusCodeException;

import com.binance.account.api.UserApi;
import com.binance.account.api.UserInfoApi;
import com.binance.account.api.UserSecurityApi;
import com.binance.account.api.UserSecurityLogApi;
import com.binance.account.vo.user.request.UpdateAgentRewardRatioRequest;
import com.binance.account.vo.user.response.GetUserResponse;
import com.binance.master.error.BusinessException;
import com.binance.master.error.GeneralCode;
import com.binance.master.utils.StringUtils;
import com.binance.mbxgateway.data.mapper.ApiModelMapper;
import com.binance.mbxgateway.data.mapper.OperateLogModelMapper;
import com.binance.mbxgateway.vo.ApiKeyInfoVo;
import com.binance.mbxgateway.vo.response.BlanceLedgerResponse;
import com.binance.mbxgateway.vo.response.TradingAccountResponse;
import com.binance.mbxgateway.web.service.IAccountService;
import com.binance.mbxgateway.web.service.IMatchboxService;
import com.binance.mbxgateway.web.service.IOperateLogService;
import com.binance.mbxgateway.web.utils.Constants;
import com.binance.mbxgateway.web.utils.MatchboxReturnUtils;
import com.binance.messaging.api.msg.MsgApi;
import com.binance.sysconf.service.SysConfigVarCacheService;

import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
public class AccountServiceImpl extends BaseServiceImpl implements IAccountService {

    @Resource
    private UserApi userApi;
    @Resource
    private UserInfoApi userInfoApi;
    @Resource
    private UserSecurityApi userSecurityApi;
    @Resource
    private UserSecurityLogApi userSecurityLogApi;

    @Resource
    private MsgApi msgApi;

    @Autowired
    private IMatchboxService matchboxService;

    @Autowired
    private SysConfigVarCacheService sysConfigVarCacheService;
    @Resource
    private Environment env;
    @Resource
    private ApiModelMapper apiModelMapper;
    @Resource
    private OperateLogModelMapper operateLogModelMapper;
    @Resource
    private IOperateLogService operateLogService;

    @Override
    public List<BlanceLedgerResponse> getBlanceLedger(String userId, String asset, Date startTime, Date endTime)
            throws Exception {
        GetUserResponse userResponse = this.getCheckedUser(userId);
        try {
            String json = this.matchboxService.getBalanceLedger(userResponse.getUserInfo().getTradingAccount(), asset,
                    endTime.getTime(), startTime.getTime());
            return MatchboxReturnUtils.getMbxValueAsList(json, BlanceLedgerResponse.class);
        } catch (HttpStatusCodeException e) {
            String json = e.getResponseBodyAsString();
            log.error("查询撮合出入金失败 is error:{},{}", json, e);
            throw new BusinessException(json);
        } catch (Exception e) {
            log.error("查询撮合出入金失败");
            throw e;
        }
    }

    @Override
    public void unlockApiTrade(String userId) throws Exception {
        GetUserResponse userResponse = this.getCheckedUser(userId);
        try {
            this.matchboxService.deleteApiKeyLock(userResponse.getUserInfo().getTradingAccount(), true);
        } catch (HttpStatusCodeException e) {
            String json = e.getResponseBodyAsString();
            log.error("解锁api交易失败 is error:{},{}", json, e);
            throw new BusinessException(json);
        } catch (Exception e) {
            log.error("解锁api交易失败");
            throw e;
        }
    }

    @Override
    public void lockApiTrade(String userId) throws Exception {
        GetUserResponse userResponse = this.getCheckedUser(userId);
        try {
            this.matchboxService.putApiKeyLock(userResponse.getUserInfo().getTradingAccount());
        } catch (HttpStatusCodeException e) {
            String json = e.getResponseBodyAsString();
            log.error("锁定api交易失败 is error:{},{}", json, e);
            throw new BusinessException(json);
        } catch (Exception e) {
            log.error("锁定api交易失败", e);
            throw e;
        }
    }

    @Override
    public ApiKeyInfoVo getApiCheck(String xMbxApiKey, String userId, String ip, String payload, Long recvWindow,
            Long timestamp, String signature) throws Exception {
        if (StringUtils.equals("1", this.sysConfigVarCacheService.getValue(Constants.SYSTEM_MAINTENANCE))) {
            throw new BusinessException(GeneralCode.SYS_MAINTENANCE);
        }
        // 仅仅是验证用户是否存在
        this.getCheckedUser(userId);
        String json = null;
        try {
            json =
                    this.matchboxService.getApiKeyCheck(xMbxApiKey, ip, payload, recvWindow, signature, timestamp);
            return MatchboxReturnUtils.getMbxValue(json, ApiKeyInfoVo.class);
        } catch (HttpStatusCodeException e) {
            json = e.getResponseBodyAsString();
            log.error("获取签名验证失败 is error:{},{}", json, e);
            throw new BusinessException(json);
        } catch (Exception e) {
            if(StringUtils.isNotBlank(json)){
                log.error("获取签名验证失败:{},{}",json,e);
                throw new BusinessException(json);
            }else{
                log.error("获取签名验证失败:",e);
                throw e;
            }
        }
    }

    @Override
    public void setTrade(String userId, Boolean canTrade) throws Exception {
        GetUserResponse userResponse = this.getCheckedUser(userId);
        try {
            this.matchboxService.putAccount(userResponse.getUserInfo().getTradingAccount(), true, canTrade, true);
        } catch (HttpStatusCodeException e) {
            String json = e.getResponseBodyAsString();
            log.error("设置是否可以交易失败 is error:{},{}", json, e);
            throw new BusinessException(json);
        } catch (Exception e) {
            log.error("设置是否可以交易失败");
            throw e;
        }
    }

    @Override
    public void setGas(String userId, Boolean isUseBnbFee) throws Exception {
        GetUserResponse userResponse = this.getCheckedUser(userId);
        try {
            if (isUseBnbFee) {
                // 自动
                this.matchboxService.deleteGasOptOut(userResponse.getUserInfo().getTradingAccount());
            } else {
                // 锁定（设置例外）
                this.matchboxService.putGasOptOut(userResponse.getUserInfo().getTradingAccount());
            }
        } catch (HttpStatusCodeException e) {
            String json = e.getResponseBodyAsString();
            log.error("setGas is error:{},{}", json, e);
            throw new BusinessException(json);
        } catch (Exception e) {
            log.error("setGas excepiton:", e);
            throw e;
        }
    }

    @Override
    public TradingAccountResponse getAccount(String userId) throws Exception {
        GetUserResponse userResponse = this.getCheckedUser(userId);
        try {
            String json = this.matchboxService.getAccount(userResponse.getUserInfo().getTradingAccount());
            return MatchboxReturnUtils.getMbxValue(json, TradingAccountResponse.class);
        } catch (HttpStatusCodeException e) {
            String json = e.getResponseBodyAsString();
            log.error("getAccount is error:{},{}", json, e);
            throw new BusinessException(json);
        } catch (Exception e) {
            log.error("getAccount excepiton:", e);
            throw e;
        }
    }

    @Override
    public void activateAccount(String userId, Boolean canTrade, Boolean canWithdraw, Boolean canDeposit)
            throws Exception {
        GetUserResponse userResponse = this.getCheckedUser(userId);
        try {

            this.matchboxService.putAccount(userResponse.getUserInfo().getTradingAccount(), canDeposit, canTrade,
                    canWithdraw);
        } catch (HttpStatusCodeException e) {
            String json = e.getResponseBodyAsString();
            log.error("activateAccount is error:{},{}", json, e);
            throw new BusinessException(json);
        } catch (Exception e) {
            log.error("activateAccount excepiton:", e);
            throw e;
        }
    }

    @Resource
    private UserModelMapper userModelMapper;

    @Override
    public void setAgentFee(String userId, BigDecimal ratio) throws Exception {
        UpdateAgentRewardRatioRequest body = new UpdateAgentRewardRatioRequest();
        body.setUserId(Long.parseLong(userId));
        body.setAgentRewardRatio(ratio);
        this.getAPIRequestResponse(this.userInfoApi.updateAgentRewardRatio(this.newAPIRequest(body)));

        // 同步数据到pnk库
        try {
            this.userModelMapper.setAgentFee(ratio, userId);
        } catch (Exception e) {
            log.warn("同步返佣比例到pnk库出现异常：userId={},ratio={},exception={}", userId, ratio, e);
        }
    }

    @Override
    public void saveApiRule(String userId, String keyId, String ip) throws Exception {
        if (StringUtils.equals("1", this.sysConfigVarCacheService.getValue(Constants.SYSTEM_MAINTENANCE))) {
            throw new BusinessException(GeneralCode.SYS_MAINTENANCE);
        }
        GetUserResponse userResponse = this.getCheckedUser(userId);
        try {
            this.matchboxService.postApiKeyRule(userResponse.getUserInfo().getTradingAccount(), ip, keyId);
        } catch (HttpStatusCodeException e) {
            log.error("saveApiRule is error:{}", e.getResponseBodyAsString());
            throw new BusinessException(GeneralCode.KEY_DELETE_READ_KEY_FAILED);
        } catch (Exception e) {
            log.error("saveApiRule excepiton:", e);
            throw new BusinessException(GeneralCode.KEY_DELETE_READ_KEY_FAILED);
        }
    }

    @Override
    public void deleteRuleByRuleId(String userId, String keyId, String ruleId) throws Exception {
        if (StringUtils.equals("1", this.sysConfigVarCacheService.getValue(Constants.SYSTEM_MAINTENANCE))) {
            throw new BusinessException(GeneralCode.SYS_MAINTENANCE);
        }
        GetUserResponse userResponse = this.getCheckedUser(userId);
        try {
            this.matchboxService.deleteApiKeyRule(userResponse.getUserInfo().getTradingAccount(), keyId, ruleId);
        } catch (HttpStatusCodeException e) {
            log.error("deleteRuleByRuleId is error:{}", e.getResponseBodyAsString());
            throw new BusinessException(GeneralCode.KEY_DELETE_READ_KEY_FAILED);
        } catch (Exception e) {
            log.error("deleteRuleByRuleId excepiton:", e);
            throw new BusinessException(GeneralCode.KEY_DELETE_READ_KEY_FAILED);
        }
    }

    @Override
    public List<ApiKeyInfoVo> getApiInfo(String userId) throws Exception {
        if (StringUtils.equals("1", this.sysConfigVarCacheService.getValue(Constants.SYSTEM_MAINTENANCE))) {
            throw new BusinessException(GeneralCode.SYS_MAINTENANCE);
        }
        GetUserResponse userResponse = this.getCheckedUser(userId);
        try {
            String json = this.matchboxService.getApiKeys(userResponse.getUserInfo().getTradingAccount());
            return MatchboxReturnUtils.getMbxValueAsList(json, ApiKeyInfoVo.class);
        } catch (HttpStatusCodeException e) {
            String json = e.getResponseBodyAsString();
            log.error("getApiInfo is error:{},{}", json, e);
            throw new BusinessException(json);
        } catch (Exception e) {
            log.error("getApiInfo excepiton:", e);
            throw e;
        }
    }

}
